package online.niuma.xiaocubao.handler;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import online.niuma.xiaocubao.common.Constants;
import online.niuma.xiaocubao.pojo.vo.ErrorCode;
import online.niuma.xiaocubao.pojo.vo.LoginUserVo;
import online.niuma.xiaocubao.pojo.vo.Result;
import online.niuma.xiaocubao.service.LoginService;
import online.niuma.xiaocubao.utils.UserThreadLocal;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 一颗蛋50斤
 * IntelliJ IDEA
 */
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Resource
    private LoginService loginService;

    // 访问控制器后执行

    @Override
    public void postHandle(@NotNull HttpServletRequest request,
                           @NotNull HttpServletResponse response,
                           @NotNull Object handler, ModelAndView modelAndView)
            throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    // 方法执行完之后执行

    @Override
    public void afterCompletion(@NotNull HttpServletRequest request,
                                @NotNull HttpServletResponse response,
                                @NotNull Object handler, Exception ex) {
        // 将使用完的本地线程进行移除，否者会造成内存溢出问题
        UserThreadLocal.remove();
    }

    // 在指定 controller 之前执行

    @Override
    public boolean preHandle(@NotNull HttpServletRequest request,
                             @NotNull HttpServletResponse response,
                             @NotNull Object handler)
            throws Exception {

        /*
        判断请求的路径是否为 HandlerMethod (Controller 方法)
        判断 token 是否为空，如果为空，则是用户未登录
        如果 token 不为空，登录验证 LoginService checkToken
        认证成功便放行
         */
        if (!(handler instanceof HandlerMethod)) {
            // handler 可能是 RequestSourceHandler
            return true;
        }
        // 获取到请求中携带的 token
        String token = request.getHeader(Constants.HEAD_TOKEN);

        log.info("================== request start =====================");
        String requestUri = request.getRequestURI();
        log.info("request uri:{}", requestUri);
        log.info("request method:{}", request.getMethod());
        log.info("token:{}", token);
        log.info("================== request end =====================");

        // 如果 token 值不存在，则表示用户是未登陆状态
        if (StringUtils.isBlank(token)) {
            Result result = Result.fail(ErrorCode.NO_LOGIN.getCode(), ErrorCode.NO_LOGIN.getMsg());
            log.warn("user no login");
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().print(JSON.toJSONString(result));
            return false;
        }
        // 验证用户的 token
        LoginUserVo loginUserInfo = loginService.checkToken(token);
        // 如果 loginUserInfo 为空，则表示验证失败
        if (loginUserInfo == null) {
            log.warn("user no login");
            Result result = Result.fail(ErrorCode.NO_LOGIN.getCode(), ErrorCode.NO_LOGIN.getMsg());
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().print(JSON.toJSONString(result));
            return false;
        }
        // 希望在 controller 中直接获取到用户的信息
        UserThreadLocal.put(loginUserInfo);

        return true;
    }
}
